#include "../include/Buffer.h"

Buffer::Buffer() : _buffer(size), _read_offset(0), _write_offset(0) {}

char *Buffer::Begin() { return &(*_buffer.begin()); }

char *Buffer::getReadOffset() { return Begin() + _read_offset; }

char *Buffer::getWriteOffset() { return Begin() + _write_offset; }

uint64_t Buffer::getPrevSpace() { return _read_offset; }

uint64_t Buffer::getTailSpace() { return static_cast<uint64_t>(_buffer.size()) - _write_offset; }

uint64_t Buffer::ReadableSpace() { return _write_offset - _read_offset; }

uint64_t Buffer::WriteableSpace() { return static_cast<uint64_t>(_buffer.size()) - _write_offset; }

void Buffer::EnsureWriteAbleSpace(uint64_t len)
{
    if (getTailSpace() >= len)
        return;
    if (getPrevSpace() + getTailSpace() >= len)
    {
        uint64_t r = ReadableSpace();
        std::copy(getReadOffset(), getReadOffset() + r, Begin());
        _read_offset = 0;
        _write_offset = r;
    }
    else
    {
        DBG_LOG("RESIZE %ld", _write_offset + len);

        // 可能之前扩len*2太大了，系统崩溃了,之前的测试问题也绝对是这里的，扩容太大导致浪费，系统资源耗尽了
        _buffer.resize(_write_offset + len);
    }
}

void Buffer::MoveWriteOffset(uint64_t offset)
{
    if (offset == 0)
        return;
    assert(offset <= getTailSpace());
    _write_offset += offset;
}

void Buffer::MoveReadOffset(uint64_t offset)
{
    if (offset == 0)
        return;
    assert(offset <= ReadableSpace());
    _read_offset += offset;
}

void Buffer::Write(const void *data, uint64_t len)
{
    if (len == 0)
        return;
    EnsureWriteAbleSpace(len);
    const char *d = (const char *)data;
    std::copy(d, d + len, getWriteOffset());
}

void Buffer::WriteAndPush(const void *data, uint64_t len)
{
    Write(data, len);
    MoveWriteOffset(len);
}

void Buffer::WriteString(const std::string &data)
{
    Write(data.c_str(), data.length());
}

void Buffer::WriteStringAndPush(const std::string &data)
{
    Write(data.c_str(), data.length());
    MoveWriteOffset(data.size());
}

void Buffer::WriteBuffer(Buffer &data)
{
    Write(data.getReadOffset(), data.ReadableSpace());
}

void Buffer::WriteBufferAndPush(Buffer &data)
{
    WriteBuffer(data);
    MoveWriteOffset(data.ReadableSpace());
}

void Buffer::Read(void *buf, uint64_t len)
{
    assert(len <= ReadableSpace());
    std::copy(getReadOffset(), getReadOffset() + len, (char *)buf);
}

void Buffer::ReadAndPop(void *buf, uint64_t len)
{
    Read(buf, len);
    MoveReadOffset(len);
}

std::string Buffer::ReadAsString(uint64_t len)
{
    assert(len <= ReadableSpace());
    std::string str;
    str.resize(len);
    Read(&str[0], len);
    return str;
}

std::string Buffer::ReadAsStringAndPop(uint64_t len)
{
    assert(len <= ReadableSpace());
    std::string str = ReadAsString(len);
    MoveReadOffset(len);
    return str;
}

char *Buffer::FindCRLF()
{
    if (ReadableSpace() == 0u)
        return nullptr;
    char *res = (char *)memchr(getReadOffset(), '\n', ReadableSpace());
    return res;
}

std::string Buffer::GetLine()
{
    char *pos = FindCRLF();
    if (pos == nullptr)
        return "";
    return ReadAsString(pos - getReadOffset() + 1);
}

std::string Buffer::GetLineAndPop()
{
    std::string res = GetLine();
    MoveReadOffset(res.size());
    return res;
}

void Buffer::clear()
{
    _read_offset = _write_offset = 0;
}
